﻿using System;
using System.Configuration;
using System.Globalization;
using System.Threading;

using BizElements.BusinessLayer;

namespace BizElements.Web
{
    #region Documentation.
    /// <summary>Reads customized user interface messages for <see cref="SearchView"/> control from a <see cref="ITextSource"/> object.</summary>
    /// <remarks><para>Values returned from SearchViewTextSource objects override values set through SearchView's properties. If a 
    /// SearchViewTextSource property returns null then no override occurs, i.e. a value set through SearchView property or a skin file is used.</para>
    /// <para>Settings are read from the application's config file as shown in the following example:
    /// <code>
    /// <configuration>
    ///     <appSettings>
    ///         <add key="BizElements.Web.SearchViewTextSource.GetDefaultTextSourceMethodAssembly" value="BizElements.Web" />
    ///         <add key="BizElements.Web.SearchViewTextSource.GetDefaultTextSourceMethodClass" value="BizElements.Web.CommonGetters"/>
    ///         <add key="BizElements.Web.SearchViewTextSource.GetDefaultTextSourceMethodName" value="GetMessageSource" />
    ///         <add key="BizElements.Web.SearchViewTextSource.DefaultKeyPrefix" value="SearchView_" />
    ///         <add key="BizElements.Web.SearchViewTextSource.GetUiCultureAssembly" value="BizElements.Web" />
    ///         <add key="BizElements.Web.SearchViewTextSource.GetUiCultureClass" value="BizElements.Web.CommonGetters"/>
    ///         <add key="BizElements.Web.SearchViewTextSource.GetUiCultureMethodName" value="GetUiCulture" />
    ///     </appSettings>
    /// </configuration>
    /// </code></para>
    /// </remarks>
    #endregion
    public class SearchViewTextSource : ISearchViewTextSource
    {
        #region Configuration.

        /// <summary>A method which gets default source of captions configured in application configuration file. If not set then <see cref="CommonGetters.GetMessageSource()"/> is used.</summary>
        /// <remarks>Settings are read from the application's config file as shown in the following example:
        /// <code>
        /// <configuration>
        ///     <appSettings>
        ///         <add key="BizElements.Web.SearchViewTextSource.GetDefaultTextSourceMethodAssembly" value="BizElements.Web" />
        ///         <add key="BizElements.Web.SearchViewTextSource.GetDefaultTextSourceMethodClass" value="BizElements.Web.CommonGetters"/>
        ///         <add key="BizElements.Web.SearchViewTextSource.GetDefaultTextSourceMethodName" value="GetMessageSource" />
        ///     </appSettings>
        /// </configuration>
        /// </code>
        /// </remarks>
        public static readonly Delegates.Function<ITextSource> GetDefaultTextSource;

        /// <summary>Default key prefix for properties/captions retrieved from text source. Defaut is <b>SearchView_</b></summary>
        /// <remarks>Settings are read from the application's config file as shown in the following example:
        /// <code>
        /// <configuration>
        ///     <appSettings>
        ///         <add key="BizElements.Web.SearchViewTextSource.DefaultKeyPrefix" value="SearchView_" />
        ///     </appSettings>
        /// </configuration>
        /// </code>
        /// </remarks>
        public static readonly string DefaultKeyPrefix;

        /// <summary>A method which gets a culture used by current user. If not set then <see cref="CommonGetters.GetUiCulture()"/> is used.</summary>
        /// <remarks>Settings are read from the application's config file as shown in the following example:
        /// <code>
        /// <configuration>
        ///     <appSettings>
        ///         <add key="BizElements.Web.SearchViewTextSource.GetUiCultureAssembly" value="BizElements.Web" />
        ///         <add key="BizElements.Web.SearchViewTextSource.GetUiCultureClass" value="BizElements.Web.CommonGetters"/>
        ///         <add key="BizElements.Web.SearchViewTextSource.GetUiCultureMethodName" value="GetUiCulture" />
        ///     </appSettings>
        /// </configuration>
        /// </code>
        /// </remarks>
        public static readonly Delegates.Function<CultureInfo> GetUiCulture;

        static SearchViewTextSource()
        {
            DefaultKeyPrefix = ConfigurationManager.AppSettings["BizElements.Web.SearchViewTextSource.DefaultKeyPrefix"];
            if (string.IsNullOrEmpty(DefaultKeyPrefix))
                DefaultKeyPrefix = "SearchView_";

            GetDefaultTextSource = ReflectionUtil.TryCreateDelegateFromAppSettings<Delegates.Function<ITextSource>>(
                "BizElements.Web.SearchViewTextSource.GetDefaultTextSourceMethodAssembly",
                "BizElements.Web.SearchViewTextSource.GetDefaultTextSourceMethodClass",
                "BizElements.Web.SearchViewTextSource.GetDefaultTextSourceMethodName");
            if (GetDefaultTextSource == null)
                GetDefaultTextSource = CommonGetters.GetMessageSource;

            GetUiCulture = ReflectionUtil.TryCreateDelegateFromAppSettings<Delegates.Function<CultureInfo>>(
                "BizElements.Web.SearchViewTextSource.GetUiCultureAssembly",
                "BizElements.Web.SearchViewTextSource.GetUiCultureClass",
                "BizElements.Web.SearchViewTextSource.GetUiCultureMethodName");
            if (GetUiCulture == null)
                GetUiCulture = CommonGetters.GetUiCulture;
        }

        #endregion

        #region Constructors.

        /// <summary>Initializes a new instance of the <b>SearchViewTextSource</b> class.</summary>
        /// <remarks><see cref="TextSource"/> property or <see cref="GetDefaultTextSource"/> delegate must be initialized before <b>SearchViewTextSource</b> can be used.</remarks>
        public SearchViewTextSource()
        {
            this.keyPrefix = DefaultKeyPrefix;
        }

        /// <summary>Initializes a new instance of the <b>SearchViewTextSource</b> class.</summary>
        /// <param name="textSource">The source of captions. <b>null</b> is not allowed.</param>
        public SearchViewTextSource(ITextSource textSource)
        {
            if (textSource == null) throw new ArgumentNullException("textSource", "textSource may not be a null reference.");
            this.textSource = textSource;
            this.keyPrefix = DefaultKeyPrefix;
        }

        /// <summary>Initializes a new instance of the <b>SearchViewTextSource</b> class.</summary>
        /// <param name="textSource">The source of captions. <b>null</b> is not allowed.</param>
        /// <param name="keyPrefix">Key prefix for properties/captions retrieved from text source.</param>
        public SearchViewTextSource(ITextSource textSource, string keyPrefix)
        {
            if (textSource == null) throw new ArgumentNullException("textSource", "textSource may not be a null reference.");
            this.textSource = textSource;
            this.keyPrefix = keyPrefix;
        }

        #endregion

        #region TextSource.

        private string GetProperty(string property)
        {
            if (this.KeyPrefix != null)
                return this.TextSource.GetString(string.Format("{0}{1}", this.KeyPrefix, property), GetCulture());
            else
                return this.TextSource.GetString(property, GetCulture());
        }

        private static CultureInfo GetCulture()
        {
            if (GetUiCulture != null)
                return GetUiCulture();
            else
                return Thread.CurrentThread.CurrentUICulture;
        }

        ITextSource textSource;

        private void EnsureTextSource()
        {
            if (this.textSource == null)
            {
                if (GetDefaultTextSource == null)
                    throw new InvalidOperationException("GetDefaultTextSource delegate is not configured in application's configuration file.");

                this.textSource = GetDefaultTextSource();
            }
        }

        /// <summary>Gets or sets source of captions.</summary>
        public ITextSource TextSource
        {
            get
            {
                EnsureTextSource();
                return this.textSource;
            }
            set
            {
                if (value == null) throw new ArgumentNullException("value", "value may not be a null reference.");
                this.textSource = value;
            }
        }

        string keyPrefix;

        /// <summary>Gets or sets key prefix for properties/captions retrieved from text source.</summary>
        /// <value>String; default is null.</value>
        /// <remarks>If prefix is not set, then it is assumed that property names are used in text source. 
        /// For example, if no prefix is defined, then key used for <b>AddWithOrText</b> property would be <b>AddWithOrText</b>.
        /// If, for example, key prefix is set to <b>MyView_</b>, then the value is stored under <b>MyView_AddWithOrText</b> key.</remarks>
        public string KeyPrefix
        {
            get { return this.keyPrefix; }
            set { this.keyPrefix = value; }
        }

        #endregion

        #region ISearchViewTextSource.

        /// <summary>Gets or sets the format of the message which displays the total count of records matching the filter criteria.</summary>
        public string RecordCountFormat
        {
            get { return GetProperty("RecordCountFormat"); }
        }

        #endregion
    }
}